﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Projet_IMA.Base;
using Projet_IMA.Unsafe;
using Projet_IMA.Projections;

namespace Projet_IMA.Environnement
{
    public unsafe partial class View3D : UserControl
    {
        private UnsafeBitmap UnsafeBitmap;
        private ZBuffer ZBuffer;
        private Scene3D Scene3D;
        private ProjectionBase Projection, ProjectionGrilleOrthogonale;
        private int startx, starty;
        private bool inMotion = false;

        public View3D(Scene3D Scene3D, EProjection projection)
        {
            InitializeComponent();

            this.UnsafeBitmap = new UnsafeBitmap();
            this.pictureBox1.Image = UnsafeBitmap.Bitmap;
            this.ZBuffer = new ZBuffer(pictureBox1.Width, pictureBox1.Height);
            this.ProjectionGrilleOrthogonale = new ProjectionOrthogonaleFace();
            this.ProjectionGrilleOrthogonale.ZeroY = 1080;
            this.Scene3D = Scene3D;

            this.ComboProjection.DataSource = ProjectionLoader.GetAllProjection();
            this.ComboProjection.DisplayMember = "Name";
            this.ComboProjection.ValueMember = "EProjection";

            this.ComboProjection.SelectedValue = projection;
        }

        private void StartDraw()
        {
            this.ZBuffer.Init();
            this.UnsafeBitmap.StartDraw();
        }

        public void Draw()
        {
            DateTime d = DateTime.Now;

            this.StartDraw();

            Projection.ZeroX = this.pictureBox1.Width / 2;
            Projection.ZeroY = this.pictureBox1.Height / 2;

            DrawCaches(Scene3D.GetCacheRepere(), Projection);
            DrawCaches(Scene3D.GetCacheObject(), Projection);

            if (this.DisplayGrid.Checked)
                if (Projection.EProjectionType == EProjectionType.Orthogonale)
                    DrawCaches(Scene3D.GetCacheGrille(Projection.EProjectionType), ProjectionGrilleOrthogonale);
                else
                    DrawCaches(Scene3D.GetCacheGrille(Projection.EProjectionType), Projection);

            this.EndDraw();
            
            Console.WriteLine((DateTime.Now - d).TotalMilliseconds);
        }

        private void DrawCaches(List<CachePoint> caches, ProjectionBase projection)
        {
            UnsafePoint3D* p_p;
            UnsafeColor* p_c;
            UnsafePoint2D* projectionPoint = (UnsafePoint2D*)Unsafe.UnmanagedMemory.New<UnsafePoint3D>(1);

            foreach (CachePoint cache in caches)
            {
                p_p = cache.p_p;
                p_c = cache.p_c;

                for (int i = 0; i < cache.Lenght; i++)
                {
                    projection.GetProjection(&p_p[i], projectionPoint);

                    if (ZBuffer.check(projectionPoint))
                        this.UnsafeBitmap.SetPixel(projectionPoint->x, projectionPoint->y, &p_c[i]);
                }
            }

            Unsafe.UnmanagedMemory.Free(projectionPoint);
        }

        private void EndDraw()
        {
            this.UnsafeBitmap.EndDraw();
            this.pictureBox1.Refresh();
            this.pictureBox1.Update();
            this.ZBuffer.Dispose();
        }

        private void ComboProjection_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.Projection = (ProjectionBase)this.ComboProjection.SelectedItem;

            if (Projection.EProjectionType == EProjectionType.Orthogonale)
            {
                ((ProjectionOrthogonale)Projection).dX = 0;
                ((ProjectionOrthogonale)Projection).dY = 0;
            }

            this.Projection.setCameraDirection(this.Scene3D.CameraDirection);
            this.Draw();
        }

        private void pictureBox1_SizeChanged(object sender, EventArgs e)
        {
            this.ZBuffer.setDimention(pictureBox1.Width, pictureBox1.Height);
            this.Draw();
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            this.inMotion = true;

            if (Projection.EProjectionType == EProjectionType.Orthogonale)
            {
                this.startx = e.X + ((ProjectionOrthogonale)Projection).dX;
                this.starty = e.Y + ((ProjectionOrthogonale)Projection).dY;
            }
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.inMotion)
            {
                if (Projection.EProjectionType == EProjectionType.Orthogonale)
                {
                    ((ProjectionOrthogonale)Projection).dX = startx - e.X;
                    ((ProjectionOrthogonale)Projection).dY = starty - e.Y;
                }

                this.Draw();
            }
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            this.inMotion = false;
        }

        private void DisplayGrid_CheckedChanged(object sender, EventArgs e)
        {
            this.Draw();
        }
    }
}
